package GA_Test;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.util.ArrayList;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

import static java.util.Collections.sort;

/**
 * 遗传算法类   输入：种群  输出：最优个体
 * 包含：
 * 1.run 开始跑算法
 * 2.createBeginningSpecies 创建种群
 * 3.calRate 计算每一种物种被选中的概率
 * 4.select 轮盘策略 选择适应度高的物种
 * 5.crossover 染色体交叉
 * 6.mutate 染色体变异
 * 7.getBestRoute 获得适应度最大的物种
 */

public class GeneticAlgorithm {

    //开始遗传
    public double run(SpeciesPopulation list) {
//创建初始种群

        createBeginningSpecies(list);
        double global_opt_solution = calRate(list);//这里应该返回一个初始的全局最优解
        //模拟退火加在这里
        float now_tem = GAData.Tem;
        float end_tem = GAData.TemEnd;
        while (now_tem > end_tem) {
            for (int i = 1; i <= GAData.Develop_Num; i++) {
                //选择

                SpeciesPopulation new_list = select(list);
                //这里增加一个自适应规则  用轮盘赌的方式去选择  对结果提升效率高的算子 被中的几率更大
                new_list = Adaptive_Operate2.run(new_list,now_tem);

                //new_list = Operators_different_1_2.different_change(new_list, now_tem);
                double new_best_solution = calRate(new_list);//获取当前最新种群中的最优解
                //下面这段注释  主要是为了获取 真个算法中最好的那个 解
//                Set set = new TreeSet<Integer>();
//             if(new_best_solution<=global_opt_solution){ //如果 执行完算子的个体解 比全局最好的解要好
//                    global_opt_solution = new_best_solution;   //更改全局最好的解
//                    for(int k=0;k<new_list.specPopu.size();k++){
//                        if(new_best_solution == new_list.specPopu.get(k).individual_runtime){//这里找到了最好的个体是哪个
//                            ArrayList<Object> trucks = new_list.specPopu.get(k).TruckGenes;
//                            ArrayList<Object> drones = new_list.specPopu.get(k).DroneGenes;
//                            new_list.best_Individual_trucks = new_list.specPopu.get(k).TruckGenes;
//                            new_list.best_Individual_drones = new_list.specPopu.get(k).DroneGenes;
//                           for(int a = 0; a<trucks.size();a++){
//                               ArrayList<Integer> truck = (ArrayList<Integer>) trucks.get(a);
//                               for(int b = 0;b<truck.size();b++){
//                                   set.add(truck.get(b));
//                               }
//                           }
//                            for(int a = 0; a<drones.size();a++){
//                                ArrayList<Integer> drone = (ArrayList<Integer>) drones.get(a);
//                                for(int b = 0;b<drone.size();b++){
//                                    set.add(drone.get(b));
//                                }
//                            }
//                          //  System.out.print(trucks);
//                           // System.out.print(drones);
//                            //System.out.println("访问点数-->" + set.size());
//                            break;
//                        }
//                    }
//                }
            //if(set.size()==GAData.cusInfo.length) {
                 global_opt_solution = (new_best_solution < global_opt_solution ? new_best_solution : global_opt_solution);//全局最优解的替换
            // }
                list = list_update(new_list, list); //这里应该调用这个方法 去更新list中的个体将新生成的new list全部复制 从开始备份的begin中 随机选择20个放进去
              //  System.out.println("当前为进化第"+ i+"代" + "全局最优解为" + global_opt_solution);
            }
            now_tem = now_tem * 0.95f;
           // System.out.println("当前温度为" + now_tem);
        }
        //System.out.println(global_opt_solution);
        return global_opt_solution;
    }

    private SpeciesPopulation list_update(SpeciesPopulation new_list, SpeciesPopulation list) {
        /**
         * 本方法用于对 参加select的list进行更新
         * 在new_list的基础上 从原来的list中随机挑出20个个体 生成新的list  用于下一轮 进化的list集
         */
        for (int i = 1; i <= GAData.Population_Num*(1-GAData.selected_num); i++) {
            Random random = new Random();
            int a = random.nextInt(list.specPopu.size() - 1);//生成一个随机数
            SpeciesIndividual al = list.specPopu.get(a).clone();//随机取一个个体并克隆
            new_list.add(al);//将这个新的个体 放进newlist中
        }
        return new_list;
    }

    //创建初始种群
    public void createBeginningSpecies(SpeciesPopulation list)//给这个种群list 添加个体
    {

        int population_num = (int) (GAData.Population_Num);
        for (int i = 1; i <= population_num; i++) {

            SpeciesIndividual individual = new SpeciesIndividual();//创建结点
            individual.createIndividual_greedy();//初始种群基因
            list.add(individual);//添加物种
        }

        //System.out.println("种群中的个体数为：" + list.specPopu.size());
    }



    //计算每一物种被选中的概率
    public double calRate(SpeciesPopulation list)//这个方法返回了种群中最好的个体  同时计算了每个个体的运行时间  被选中概率  个体适应度
    {
//计算总适应度
        double totalFitness = 0; //种群总适应度
        ArrayList<Double> global_solution = new ArrayList<>();
        for (int k = 0; k < list.specPopu.size(); k++) {
            list.specPopu.get(k).calFitness(); //计算选中个体的适应度
            global_solution.add(list.specPopu.get(k).individual_runtime);
            totalFitness += list.specPopu.get(k).fitness; //将该个体的适应度进行累加
        }

        sort(global_solution);
        //计算个体选中概率
        for (int m = 0; m < list.specPopu.size(); m++) {
            list.specPopu.get(m).selected_rate = list.specPopu.get(m).fitness / totalFitness; //求出每个个体被选中的概率
            //if(list.specPopu.get(m).individual_runtime == global_solution.get(0)){
            //System.out.println("当前种群最优路径所用车辆数为" + list.specPopu.get(m).TruckGenes.size());//打印出这个最优的路径用了几个车
            // }
        }
        //计算全局最优解
        return global_solution.get(0);
    }

    //选择优秀物种（轮盘赌）
    SpeciesPopulation select(SpeciesPopulation list) {
        SpeciesPopulation new_list = new SpeciesPopulation();
        for (int i = 0; i < GAData.Population_Num*GAData.selected_num; i++) {
            //产生0-1的概率

            double select_sum = 0;
            float x = (float) Math.random();//
            for (int j = 0; j < list.specPopu.size(); j++) {
                select_sum += list.specPopu.get(j).selected_rate;
                if (select_sum >= x) {
                    new_list.add(list.specPopu.get(j).clone());
                    break;
                }
            }
        }
        new_list.population_num = new_list.specPopu.size();
        return new_list;
    }

}